package com.eliza.kotlin.design.creation.single


/*-*- coding:utf-8 -*-
 * @Author  : debi
 * @Time    : 6/4/22
 * @Software: IntelliJ IDEA
 */
/**
* 对于 `getInstance()` 方法来说，绝大部分的操作都是读操作，读操作是线程安全的，所以我们没必让每个线程必须持有锁才能调用该方法，
 * 我们需要调整加锁的时机。由此也产生了一种新的实现模式：双重检查锁模式
* */
/*
* 懒汉： * 双重检查锁方式
*/
private class LazySingleton2 {

    //1，私有构造方法
    private constructor()


    companion object {
        /*init方法最终被编译成了static代码块*/

        //2，在本类中创建本类对象
        /**
         * 存在问题，在多线程的情况下，可能会出现空指针问题，出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
        要解决双重检查锁模式带来空指针异常的问题，只需要使用 `volatile` 关键字, `volatile` 关键字可以保证可见性和有序性。
         * */
        @Volatile
        private var instance: LazySingleton2? = null


        //3，提供一个公共的访问方式，让外界获取该对象
        fun getInstance(): LazySingleton2 {
            //第一次判断，如果instance的值不为null，不需要抢占锁，直接返回对象
            if (instance == null) {
                synchronized(LazySingleton2::class.java) {
                    //抢到锁之后再次判断是否为null
                    if (instance == null) {
                        instance = LazySingleton2()
                    }
                }

            }
            return instance!!

        }

    }
}
/**
 * 存在问题，在多线程的情况下，可能会出现空指针问题，出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
要解决双重检查锁模式带来空指针异常的问题，只需要使用 `volatile` 关键字, `volatile` 关键字可以保证可见性和有序性。
 * */
fun main() {

    //创建Singletion类的对象
    val instance = LazySingleton2.getInstance()

    val instance1 = LazySingleton2.getInstance()
    //判断获取到的两个是否是同一个对象
    println(instance === instance1)
}